package com.ColonyCount.Image;


import android.graphics.Point;
import android.graphics.Rect;
import android.util.Log;

public class EDM {
	
	
	public static final int ONE = 41;	// One unit distance
	public static final int SQRT2 = 58; // ~ 41 * sqrt(2)
	public static final int SQRT5 = 92; // ~ 41 * sqrt(5)	
	
	static public void createEDM(Image8 sourceMap, int thresholdMin, int thresholdMax, Image16 targetEDM) 
	{
		long time = System.currentTimeMillis();
		
        int width = sourceMap.getWidth();
        int height = sourceMap.getHeight();
        int count = width*height;
        

        // Create edm
        //short startBackgroundEDM = 255 << 7;
        short startBackgroundEDM = 32767;
        
        
        byte[] sourceMapPixels = sourceMap.pixels;
        short[] imageEDM = targetEDM.pixels;
		for(int i = 0; i < count;i++)
		{
			int iVal = sourceMapPixels[i] & 0xFF;
			
			if(iVal > thresholdMax) 
			{
				imageEDM[i] = 0;
				continue;
			}

			if(iVal < thresholdMin) 
			{
				imageEDM[i] = 0;
				continue;
			}
			
			imageEDM[i] = startBackgroundEDM;
		}
		targetEDM.maxValue = startBackgroundEDM;
		
		
        int rowsize = width;
        int xmax    = width - 2;
        int ymax    = height - 2;
        int offset;
        for (int y=0; y<height; y++) {
            for (int x=0; x<width; x++) {
                offset = x + y * rowsize;
                if (imageEDM[offset] > 0) 
                {
                    if ((x<=1) || (x>=xmax) || (y<=1) || (y>=ymax))
                        setEdgeValue(offset, rowsize, imageEDM, x, y, xmax, ymax);
                    else
                        setValue(offset, rowsize, imageEDM);
                }
            } // for x
        } // for y
        
        for (int y=height-1; y>=0; y--) {
            for (int x=width-1; x>=0; x--) {
                offset = x + y * rowsize;
                if (imageEDM[offset] > 0) {
                    if ((x<=1) || (x>=xmax) || (y<=1) || (y>=ymax))
                        setEdgeValue(offset, rowsize, imageEDM, x, y, xmax, ymax);
                    else
                        setValue(offset, rowsize, imageEDM);
                }
            } // for x
        } // for y
        
        // Calc max
        short max = 0;
        for(int i = 0; i < count;i++)
        {
        	short val = imageEDM[i];
        	if(val > max)
        	{
        		max = val;
        	}
        }
        targetEDM.maxValue = max;
        
        Log.v("", "EDM.createEDM " + (System.currentTimeMillis() - time)+ "ms");
    }	 
 
	static public void createEDM(ImageRegion region, Image16 targetEDM) 
	{
		long time = System.currentTimeMillis();
		
        // Create edm
        //short startBackgroundEDM = 255 << 7;
        short startBackgroundEDM = 32767;
        

        Rect regionBounds = region.getBounds();
        Point[] points = region.getPoints();
        for(int i=0;i<points.length;i++)
        {
        	targetEDM.setPixelValue(points[i].x - regionBounds.left, points[i].y - regionBounds.top, startBackgroundEDM);
        }
		targetEDM.maxValue = startBackgroundEDM;
		
		short[] imageEDM = targetEDM.pixels;
        int width = targetEDM.getWidth();
        int height = targetEDM.getHeight();
        int count = width*height;
        int rowsize = width;
        int xmax    = width - 2;
        int ymax    = height - 2;
        int offset;
        for (int y=0; y<height; y++) {
            for (int x=0; x<width; x++) {
                offset = x + y * rowsize;
                if (imageEDM[offset] > 0) 
                {
                    if ((x<=1) || (x>=xmax) || (y<=1) || (y>=ymax))
                        setEdgeValue(offset, rowsize, imageEDM, x, y, xmax, ymax);
                    else
                        setValue(offset, rowsize, imageEDM);
                }
            } // for x
        } // for y
        
        for (int y=height-1; y>=0; y--) {
            for (int x=width-1; x>=0; x--) {
                offset = x + y * rowsize;
                if (imageEDM[offset] > 0) {
                    if ((x<=1) || (x>=xmax) || (y<=1) || (y>=ymax))
                        setEdgeValue(offset, rowsize, imageEDM, x, y, xmax, ymax);
                    else
                        setValue(offset, rowsize, imageEDM);
                }
            } // for x
        } // for y
        
        // Calc max
        short max = 0;
        for(int i = 0; i < count;i++)
        {
        	short val = imageEDM[i];
        	if(val > max)
        	{
        		max = val;
        	}
        }
        targetEDM.maxValue = max;
        
        Log.v("", "EDM.createEDM " + (System.currentTimeMillis() - time)+ "ms");
    }	 
	
    static void setValue(int offset, int rowsize, short[] image16) {
        int  v;
        int r1  = offset - rowsize - rowsize - 2;
        int r2  = r1 + rowsize;
        int r3  = r2 + rowsize;
        int r4  = r3 + rowsize;
        int r5  = r4 + rowsize;
        int min = 32767;
        
        v = image16[r2 + 2] + ONE;
        if (v < min)
            min = v;
        v = image16[r3 + 1] + ONE;
        if (v < min)
            min = v;
        v = image16[r3 + 3] + ONE;
        if (v < min)
            min = v;
        v = image16[r4 + 2] + ONE;
        if (v < min)
            min = v;
        
        v = image16[r2 + 1] + SQRT2;
        if (v < min)
            min = v;
        v = image16[r2 + 3] + SQRT2;
        if (v < min)
            min = v;
        v = image16[r4 + 1] + SQRT2;
        if (v < min)
            min = v;
        v = image16[r4 + 3] + SQRT2;
        if (v < min)
            min = v;
        
        v = image16[r1 + 1] + SQRT5;
        if (v < min)
            min = v;
        v = image16[r1 + 3] + SQRT5;
        if (v < min)
            min = v;
        v = image16[r2 + 4] + SQRT5;
        if (v < min)
            min = v;
        v = image16[r4 + 4] + SQRT5;
        if (v < min)
            min = v;
        v = image16[r5 + 3] + SQRT5;
        if (v < min)
            min = v;
        v = image16[r5 + 1] + SQRT5;
        if (v < min)
            min = v;
        v = image16[r4] + SQRT5;
        if (v < min)
            min = v;
        v = image16[r2] + SQRT5;
        if (v < min)
            min = v;
        
        image16[offset] = (short)min;
        
    } // setValue()
    
    static void setEdgeValue(int offset, int rowsize, short[] image16, int x, int y, int xmax, int ymax) {
        int  v;
        int r1 = offset - rowsize - rowsize - 2;
        int r2 = r1 + rowsize;
        int r3 = r2 + rowsize;
        int r4 = r3 + rowsize;
        int r5 = r4 + rowsize;
        int min = 32767;
        int offimage = image16[r3 + 2];
        
        if (y<1)
            v = offimage + ONE;
        else
            v = image16[r2 + 2] + ONE;
        if (v < min)
            min = v;
        
        if (x<1)
            v = offimage + ONE;
        else
            v = image16[r3 + 1] + ONE;
        if (v < min)
            min = v;
        
        if (x>xmax)
            v = offimage + ONE;
        else
            v = image16[r3 + 3] + ONE;
        if (v < min)
            min = v;
        
        if (y>ymax)
            v = offimage + ONE;
        else
            v = image16[r4 + 2] + ONE;
        if (v < min)
            min = v;
        
        if ((x<1) || (y<1))
            v = offimage + SQRT2;
        else
            v = image16[r2 + 1] + SQRT2;
        if (v < min)
            min = v;
        
        if ((x>xmax) || (y<1))
            v = offimage + SQRT2;
        else
            v = image16[r2 + 3] + SQRT2;
        if (v < min)
            min = v;
        
        if ((x<1) || (y>ymax))
            v = offimage + SQRT2;
        else
            v = image16[r4 + 1] + SQRT2;
        if (v < min)
            min = v;
        
        if ((x>xmax) || (y>ymax))
            v = offimage + SQRT2;
        else
            v = image16[r4 + 3] + SQRT2;
        if (v < min)
            min = v;
        
        if ((x<1) || (y<=1))
            v = offimage + SQRT5;
        else
            v = image16[r1 + 1] + SQRT5;
        if (v < min)
            min = v;
        
        if ((x>xmax) || (y<=1))
            v = offimage + SQRT5;
        else
            v = image16[r1 + 3] + SQRT5;
        if (v < min)
            min = v;
        
        if ((x>=xmax) || (y<1))
            v = offimage + SQRT5;
        else
            v = image16[r2 + 4] + SQRT5;
        if (v < min)
            min = v;
        
        if ((x>=xmax) || (y>ymax))
            v = offimage + SQRT5;
        else
            v = image16[r4 + 4] + SQRT5;
        if (v < min)
            min = v;
        
        if ((x>xmax) || (y>=ymax))
            v = offimage + SQRT5;
        else
            v = image16[r5 + 3] + SQRT5;
        if (v < min)
            min = v;
        
        if ((x<1) || (y>=ymax))
            v = offimage + SQRT5;
        else
            v = image16[r5 + 1] + SQRT5;
        if (v < min)
            min = v;
        
        if ((x<=1) || (y>ymax))
            v = offimage + SQRT5;
        else
            v = image16[r4] + SQRT5;
        if (v < min)
            min = v;
        
        if ((x<=1) || (y<1))
            v = offimage + SQRT5;
        else
            v = image16[r2] + SQRT5;
        if (v < min)
            min = v;
        
        image16[offset] = (short)min;
        
    } // setEdgeValue()
}
